#ifndef __LIBC_NET_IF_H
#define __LIBC_NET_IF_H

#include <sys/socket.h>
#include <sys/types.h>
#include <ctype.h>

typedef struct if_nameidx
{
    uint32_t if_index;
    char *if_name;
} if_nameidx_t;

// internet flags
enum iff
{
    IFF_UP = 0x01,           // interface is up
    IFF_BROADCAST = 0x02,    // broadcast address valid
    IFF_DEBUG = 0x04,        // turn on debug
    IFF_LOOKBACK = 0x08,     // is lookback net
    IFF_POINTTOPOINT = 0x10, // interface is point to point link
    IFF_NOTRAILERS = 0x20,   // avoid use of trailers
    IFF_RUNNING = 0x40,      // resources allocated
    IFF_NOARP = 0x80,        // no address resolution protocol
    IFF_PROMISC = 0x100,     // receive all packet
    IFF_ALLMULTI = 0x200,    // receive all multicast packet
    IFF_MASTER = 0x400,      // master of a load balancer
    IFF_SLAVE = 0x800,       // slave of a load balancer
    IFF_MULTICAST = 0x1000,  // support multicase
    IFF_PORTSEL = 0x2000,    // can set media type
    IFF_AUTOMEDIA = 0x4000,  // auto media select device
    IFF_DYNAMIC = 0x8000,    // dialua device with changing addresses
};

typedef struct ifaddr
{
    sockaddr_t ifa_addr; // address of interface
    union
    {
        sockaddr_t ifu_broadaddr;
        sockaddr_t ifu_dstaddr;
    } ifa_ifu;
    struct ifaddr *ifa_ifp;  // back-pointer to interface
    struct ifaddr *ifa_next; // next address for interface
} ifaddr_t;

// broadcast address
#define ifa_broadcast ifa_ifu.ifu_broadcast
// other end of link
#define ifa_dstaddr ifa_ifu.ifu_dstaddr

// device map block
typedef struct ifmap
{
    uint64_t mem_start;
    uint64_t mem_end;
    uint64_t base_addr;
    uint8_t irq;
    uint8_t dma;
    uint8_t port;
} ifmap_t;

// interface request block
typedef struct ifreq
{
#define IFHWADDRLEN 6
#define IFNAMSIZ 16
    union
    {
        char ifrn_name[IFNAMSIZ]; // interface name
    } ifr_ifrn;

    union
    {
        sockaddr_t ifru_addr;
        sockaddr_t ifru_dstaddr;
        sockaddr_t ifru_broadaddr;
        sockaddr_t ifru_netmask;
        sockaddr_t ifru_hwaddr;
        uint16_t ifru_flags;
        int ifru_ivalue;
        int ifru_mtu;
        ifmap_t ifru_map;
        char ifru_slave[IFNAMSIZ];
        char ifru_newname[IFNAMSIZ];
        caddr_t ifru_data;
    } ifr_ifru;
} ifreq_t;

#define ifr_name ifr_ifrn.ifrn_name           // interface name
#define ifr_hwaddr ifr_ifru.ifru_hwaddr       // MAC address
#define ifr_addr ifr_ifru.ifru_addr           // address
#define ifr_dstaddr ifr_ifru.ifru_dstaddr     // other end of p-p link
#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
#define ifr_netmask ifr_ifru.ifru_netmask     // interface netmask
#define ifr_flags ifr_ifru.ifru_flags         // flags
#define ifr_metric ifr_ifru.ifru_ivalue       // metric
#define ifr_mtu ifr_ifru.ifru_mtu             // mtu
#define ifr_map ifr_ifru.ifru_map             // device map
#define ifr_slave ifr_ifru.ifru_slave         // slave device
#define ifr_data ifr_ifru.ifru_data           // for use by interface
#define ifr_ifindex ifr_ifru.ifru_ivalue      // interface index
#define ifr_bandwidth ifr_ifru.ifru_ivalue    // link bandwidth
#define ifr_qlen ifr_ifru.ifru_ivalue         // queue length
#define ifr_newname ifr_ifru.ifru_newname     // new name

typedef struct ifconf
{
    int ifc_len; // size of buffer
    union
    {
        char *ifcu_buff;   // input from user->kernel
        ifreq_t *ifcu_req; // return from kernel->user
    } ifc_ifcu;
} ifconf_t;

#define ifc_buff ifc_ifcu.ifcu_buff // buffer address
#define ifc_req ifc_ifcu.ifcu_req   // return array

#endif